home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 July: Mac OS SDK / Dev.CD Jul 97 SDK1.toast / Development Kits (Disc 1) / QuickDraw GX / Programming Stuff / GX Libraries / TrueTypeLibrary.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-03-31  |  25.3 KB  |  850 lines  |  [TEXT/MPS ]

  1.  
  2. /*
  3.     File:        TrueTypeLibrary.c
  4.  
  5.     Contains:    graphics libraries - TrueType routines
  6.     
  7.     Written by:    Cary Clark, Georgiann Delaney, Michael Fairman, Dave Good, Robert Johnson, Keith McGreggor, Oliver Steele, David Van Brink, Chris Yerga
  8.     
  9.     Copyright:    © 1995 by Apple Computer, Inc., all rights reserved.
  10.  
  11.     Change History (most recent first):
  12.  
  13.          <2>      1/9/95    JD        changed 'boolean' to 'Boolean'
  14.          <1>      1/9/95    JD        First checked in.
  15. */
  16.  
  17.  
  18. #include <Memory.h>
  19. #include <GXFonts.h>
  20. #include <GXGraphics.h>
  21. #include <GXMath.h>
  22. #include "TrueTypeLibrary.h"
  23.  
  24. #define AINT_WORD_ALIGN(n)  ((n) & 1)
  25. #define WORD_ALIGN(n)       (((n) + 1) & ~1L)
  26. #define AINT_LONG_ALIGN(n)  ((n) & 3)
  27. #define LONG_ALIGN(n)       (((n) + 3) & ~3L)
  28.  
  29. #define IfDebug(condition, str)     if (condition) DebugStr(str)
  30. #define CopyBytes(src, dst, count)  BlockMove((Ptr)src, (Ptr)dst, count)
  31. #define TTDisposPtr(block)      DisposePtr((Ptr)block)
  32.  
  33.  
  34. #define SFNT_MAGIC                      0x5F0F3CF5
  35. #define SHORT_INDEX_TO_LOC_FORMAT       0
  36. #define LONG_INDEX_TO_LOC_FORMAT        1
  37. #define GLYPH_DATA_FORMAT               0
  38. #define FONT_HEADER_VERSION             0x10000
  39.  
  40. typedef enum outlinePacking {
  41.     ONCURVE = 1,
  42.     XSHORT = 2,
  43.     YSHORT = 4,
  44.     REPEAT_FLAGS = 8,
  45. /* IF XSHORT */
  46.     SHORT_X_IS_POS = 16,        /* the short vector is positive */
  47. /* ELSE */
  48.     NEXT_X_IS_ZERO = 16,        /* the relative x coordinate is zero */
  49. /* ENDIF */
  50. /* IF YSHORT */
  51.     SHORT_Y_IS_POS = 32,        /* the short vector is positive */
  52. /* ELSE */
  53.     NEXT_Y_IS_ZERO = 32     /* the relative y coordinate is zero */
  54. /* ENDIF */
  55. } outlinePacking;
  56.  
  57. typedef enum componentPacking {
  58.     COMPONENTCTRCOUNT = -1,
  59.     ARG_1_AND_2_ARE_WORDS = 1,      /* if not, they are bytes */
  60.     ARGS_ARE_XY_VALUES = 2,         /* if not, they are points */
  61.     ROUND_XY_TO_GRID = 4,
  62.     WE_HAVE_A_SCALE = 8,                /* if not, Sx = Sy = 1.0 */
  63.     NON_OVERLAPPING = 16,
  64.     MORE_COMPONENTS = 32,           /* if not, this is the last one */
  65.     WE_HAVE_AN_X_AND_Y_SCALE = 64,  /* Sx != Sy */
  66.     WE_HAVE_A_TWO_BY_TWO = 128,     /* t00, t01, t10, t11 */
  67.     WE_HAVE_INSTRUCTIONS = 256,     /* short count followed by instructions follows */
  68.     USE_MY_METRICS = 512                /* use my metrics for parent glyph */
  69. } componentPacking;
  70.  
  71. typedef struct {
  72.     unsigned long               bc;
  73.     unsigned long               ad;
  74. } BigDate;
  75.  
  76. typedef struct {
  77.     Fixed                   version;            /* for this table, set to 1.0 */
  78.     Fixed                   fontRevision;       /* For Font Manufacturer */
  79.     unsigned long           checkSumAdjustment;
  80.     unsigned long           magicNumber;        /* signature, should always be 0x5F0F3CF5  == MAGIC */
  81.     unsigned short          flags;
  82.     unsigned short          unitsPerEm;         /* Specifies how many in Font Units we have per EM */
  83.  
  84.     BigDate                 created;
  85.     BigDate                 modified;
  86.  
  87.     /** This is the gxFont wide bounding box in ideal space
  88.     (baselines and metrics are NOT worked into these numbers) **/
  89.  
  90.     short                   xMin;
  91.     short                   yMin;
  92.     short                   xMax;
  93.     short                   yMax;
  94.  
  95.     unsigned short          macStyle;           /* macintosh gxStyle word */
  96.     unsigned short          lowestRecPPEM;      /* lowest recommended pixels per Em */
  97.  
  98.     /* 0: fully mixed directional glyphs, 1: only strongly L->R or T->B glyphs, 
  99.        -1: only strongly R->L or B->T glyphs, 2: like 1 but also contains neutrals,
  100.        -2: like -1 but also contains neutrals */
  101.  
  102.     short                   fontDirectionHint;
  103.  
  104.     short                   indexToLocFormat;
  105.     short                   glyphDataFormat;
  106. } sfntFontHeader;
  107.  
  108.  
  109. static Boolean EqualBytes(const void* a, const void* b, long byteCount)
  110. {
  111.     register const char* ying = (const char *) a;
  112.     register const char* yang = (const char *) b;
  113.     
  114.     while (byteCount--)
  115.         if (*ying++ != *yang++)
  116.             return false;
  117.     return true;
  118. }
  119.  
  120. static void* TTNewPtr(long size)
  121. {
  122.     void* p = NewPtr(size);
  123.     
  124.     if (p == nil || MemError())
  125.         Debugger();
  126.     return p;
  127. }
  128.  
  129. static Handle TTNewHandle(long size)
  130. {
  131.     Handle block = NewHandle(size);
  132.     
  133.     if (block == nil || MemError())
  134.         Debugger();
  135.     return block;
  136. }
  137.  
  138. static void* TTSetHandleSize(Handle block, long newSize)
  139. {
  140.     SetHandleSize(block, newSize);
  141.     if (MemError())
  142.         Debugger();
  143.     return *block;
  144. }
  145.  
  146. static void* ResizeHandle(Handle block, long offset, long delta)
  147. {
  148.     long size = GetHandleSize(block);
  149.  
  150.     if (delta > 0)
  151.     {   TTSetHandleSize(block, size + delta);
  152.         BlockMove(*block + offset, *block + offset + delta, size - offset);
  153.     }
  154.     else
  155.     {   BlockMove(*block + offset - delta, *block + offset, size - offset + delta);
  156.         TTSetHandleSize(block, size + delta);
  157.     }
  158.     return *block;
  159. }
  160.  
  161. static Handle CopyFontTable(gxFont fontID, gxFontTableTag name)
  162. {
  163.     long size, index;
  164.  
  165.     size = GXFindFontTable(fontID, name, nil, &index);
  166.     if (size)
  167.     {   Handle table = TTNewHandle(size);
  168.         HLock(table);
  169.         GXGetFontTable(fontID, index, *table, nil);
  170.         HUnlock(table);
  171.         return table;
  172.     }
  173.     return nil;
  174. }
  175.  
  176. static void* GetFontTablePtr(gxFont fontID, gxFontTableTag name)
  177. {
  178.     long size, index;
  179.  
  180.     size = GXFindFontTable(fontID, name, nil, &index);
  181.     if (size)
  182.     {   void* table = TTNewPtr(size);
  183.         GXGetFontTable(fontID, index, table, nil);
  184.         return table;
  185.     }
  186.     return nil;
  187. }
  188.  
  189. #if 0
  190. long CountFontMetrics(gxFont fontID)
  191. {
  192.     long count;
  193.     Handle table;
  194.  
  195.     count = 0;
  196.     if (table = CopyFontTable(fontID, fontMetricsTag))
  197.     {   count = ((fontMetricsHeader*)*table)->metricCount;
  198.         DisposeHandle(table);
  199.     }
  200.     return count;
  201. }
  202.  
  203. gxFontTableTag GetFontMetric(gxFont fontID, long index, long* pointIndex, long* glyphIndex)
  204. {
  205.     Handle table;
  206.     gxFontTableTag metricsTag = 0;
  207.  
  208.     if (table = CopyFontTable(fontID, fontMetricsTag))
  209.     {   fontMetricsHeader* fontMet = (fontMetricsHeader*)*table;
  210.     
  211.         if (glyphIndex)
  212.             *glyphIndex = fontMet->glyphIndex + 1;
  213.         if (index > 0 && index <= fontMet->metricCount)
  214.         {   fontWideMetric* metric = &fontMet->metric[index - 1];
  215.             metricsTag = metric->name;
  216.             if (pointIndex)
  217.                 *pointIndex = metric->pointIndex + 1;
  218.         }
  219.         DisposeHandle(table);
  220.     }
  221.     return metricsTag;
  222. }
  223.  
  224. long FindFontMetric(gxFont fontID, gxFontTableTag metricsTag, long* pointIndex, long* glyphIndex)
  225. {
  226.     Handle table;
  227.     long index = 0;
  228.  
  229.     if (table = CopyFontTable(fontID, fontMetricsTag))
  230.     {   fontMetricsHeader* fontMet = (fontMetricsHeader*)*table;
  231.         fontWideMetric* metric = fontMet->metric;
  232.         fontWideMetric* stop = metric + fontMet->metricCount;
  233.  
  234.         if (glyphIndex)
  235.             *glyphIndex = fontMet->glyphIndex + 1;
  236.         while (metric < stop)
  237.         {   if (metric->name == metricsTag)
  238.             {   index = metric - fontMet->metric + 1;
  239.                 if (pointIndex)
  240.                     *pointIndex = metric->pointIndex + 1;
  241.                 break;
  242.             }
  243.             metric++;
  244.         }
  245.         DisposeHandle(table);
  246.     }
  247.     return index;
  248. }
  249.  
  250. long SetFontMetric(gxFont fontID, long index, gxFontTableTag metricTag, long pointIndex, long glyphIndex)
  251. {
  252.     Handle table;
  253.  
  254.     if (!index && !metricTag)
  255.     {   IfDebug(true, "\pmetricTag or index must non-zero");
  256.         return 0;
  257.     }
  258.  
  259.     if (table = CopyFontTable(fontID, fontMetricsTag))
  260.     {   fontMetricsHeader* fontMet = (fontMetricsHeader*)*table;
  261.  
  262.         if (glyphIndex)
  263.             fontMet->glyphIndex = glyphIndex - 1;
  264.         if (pointIndex == 0)
  265.             goto DISPOSE_AND_EXIT;
  266.         if (index < 0 || index > fontMet->metricCount)
  267.         {   IfDebug(true, "\pindex out of range");
  268.             index = 0;
  269.             goto DISPOSE_AND_EXIT;
  270.         }
  271.         if (index == 0)
  272.         {   long offset;
  273.             fontWideMetric* metric, *stop;
  274.  
  275.             metric = fontMet->metric;
  276.             stop = metric + fontMet->metricCount;
  277.             while (metric < stop)
  278.             {   if (metric->name == metricTag)
  279.                 {   metric->pointIndex = pointIndex - 1;
  280.                     index = metric - fontMet->metric + 1;
  281.                     goto DONE;
  282.                 }
  283.                 metric++;
  284.             }
  285.             /*  MetricTag not found, append a new one.
  286.             */
  287.             offset = (char*)metric - (char*)fontMet->metric;
  288.             fontMet = ResizeHandle(table, offset, sizeof(fontWideMetric));
  289.             metric = (fontWideMetric*)((char*)fontMet->metric + offset);
  290.             metric->name = metricTag;
  291.             metric->pointIndex = pointIndex - 1;
  292.             metric->flags = 0;
  293.             index = ++fontMet->metricCount;
  294.         }
  295.         else
  296.         {   fontMet->metric[index - 1].name = metricTag;
  297.             fontMet->metric[index - 1].pointIndex = pointIndex - 1;
  298.         }
  299.     DONE:
  300.         HLock(table);
  301.         GXSetFontTable(fontID, 0, fontMetricsTag, GetHandleSize(table), fontMet);
  302.     DISPOSE_AND_EXIT:
  303.         DisposeHandle(table);
  304.     }
  305.     else        /* make a new table */
  306.     {   fontMetricsHeader* fontMet;
  307.         long size = sizeof_fontMetricsHeader + sizeof(fontWideMetric);
  308.  
  309.         table = TTNewHandle(size);
  310.         fontMet = (fontMetricsHeader*)*table;
  311.         fontMet->version = 0x10000;
  312.         fontMet->glyphIndex = glyphIndex - 1;
  313.         fontMet->metricCount = index = 1;
  314.         fontMet->metric[0].name = metricTag;
  315.         fontMet->metric[0].pointIndex = pointIndex - 1;
  316.         fontMet->metric[0].flags = 0;
  317.         HLock(table);
  318.         GXSetFontTable(fontID, 0, fontMetricsTag, size, fontMet);
  319.         DisposeHandle(table);
  320.     }
  321. EXIT:
  322.     return index;
  323. }
  324.  
  325. long DeleteFontMetric(gxFont fontID, long index, gxFontTableTag metricTag)
  326. {
  327.     Handle table;
  328.  
  329.     if (!index && !metricTag)
  330.     {   IfDebug(true, "\pmetricTag or index must be non-zero");
  331.         return 0;
  332.     }
  333.  
  334.     if (table = CopyFontTable(fontID, fontMetricsTag))
  335.     {   fontMetricsHeader* fontMet = (fontMetricsHeader*)*table;
  336.         fontWideMetric* stop, *metric;
  337.         
  338.         if (index > 0 && index <= fontMet->metricCount)
  339.         {   IfDebug(metricTag && fontMet->metric[index - 1].name != metricTag, "\pIndex and name are inconsistant");
  340.             metric = fontMet->metric + index - 1;
  341.             goto FOUND_IT;
  342.         }
  343.         else if (index != 0)
  344.         {   IfDebug(true, "\pDeleteFontMetric: index out of range");
  345.             index = 0;
  346.             goto DONE;
  347.         }
  348.         else
  349.         {   metric = fontMet->metric;
  350.             stop = metric + fontMet->metricCount;
  351.             while (metric < stop)
  352.             {   if (metric->name == metricTag)
  353.                     goto FOUND_IT;
  354.                 metric++;
  355.             }
  356.         }
  357.         goto DONE;
  358.     FOUND_IT:
  359.         fontMet = ResizeHandle(table, (char*)metric - (char*)fontMet, - sizeof(fontWideMetric));
  360.         index = --fontMet->metricCount;
  361.  
  362.         HLock(table);
  363.         GXSetFontTable(fontID, 0, fontMetricsTag, GetHandleSize(table), fontMet);
  364.     DONE:
  365.         DisposeHandle(table);
  366.     }
  367. EXIT:
  368.     return index;
  369. }
  370. #endif
  371.  
  372. /*
  373.  *  This guy only works with non-composits. This should be fixed.
  374.  */
  375. long GetFontGlyphOutline(gxFont fontID, long glyphIndex, short* contourCount, short endPoint[], unsigned char onCurve[],
  376.                         short xCoord[], short yCoord[], short* instructionCount, unsigned char instructions[],
  377.                         glyphBoundingBox* bbox)
  378. {
  379.     short* glyph, *glyphData;
  380.     long size, contours, instrCount, points = 0;
  381.  
  382.     size = GetFontGlyphData(fontID, glyphIndex, nil);
  383.     if (!size)
  384.     {   if (contourCount)
  385.             *contourCount = 0;
  386.         if (instructionCount)
  387.             *instructionCount = 0;
  388.         return 0;
  389.     }
  390.     glyphData = (short *) TTNewPtr(size);
  391.     GetFontGlyphData(fontID, glyphIndex, glyphData);
  392.  
  393.     glyph = glyphData;
  394.     contours = *glyph++;
  395.     if (contourCount)
  396.         *contourCount = contours;
  397.     if (bbox)
  398.         CopyBytes(glyph, bbox, 4 * sizeof(short));
  399.  
  400.     if (contours > 0)
  401.     {   glyph += 4;         /* bounding box */
  402.         
  403.         if (endPoint)
  404.             CopyBytes(glyph, endPoint, contours * sizeof(short));
  405.         
  406.         glyph += contours;      /* end gxPoint [] */
  407.         points = glyph[-1] + 1;
  408.  
  409.         instrCount = *glyph++;
  410.         if (instructionCount)
  411.             *instructionCount = instrCount;
  412.         if (instructions)
  413.             CopyBytes(glyph, instructions, instrCount);
  414.         glyph = (short*)((char*)glyph + instrCount);        /* glyph may now gxPoint to an odd byte, so don't use it as a (short*) */
  415.  
  416.         if (xCoord || yCoord || onCurve)
  417.         {   unsigned char* p, *byteP, *byteP2, flag, *flags;
  418.             int z;
  419.  
  420.             p = (unsigned char*)glyph;
  421.             flags = (unsigned char *) TTNewPtr(points);
  422.     
  423.             /* Do flags */
  424.             byteP = flags;
  425.             byteP2 = byteP + points;
  426.             while (byteP < byteP2)
  427.             {   *byteP++ = flag = *p++;
  428.                 if ( flag & REPEAT_FLAGS )
  429.                 {   int count = *p++;
  430.                     for (--count; count >= 0; --count)
  431.                         *byteP++ = flag;
  432.                 }
  433.             }
  434.  
  435.             if (onCurve)
  436.             {   byteP = flags;
  437.                 byteP2 = byteP + points;
  438.                 while (byteP < byteP2)
  439.                     *onCurve++ = *byteP++ & ONCURVE;
  440.             }
  441.  
  442.             /* Do X first */
  443.             z = 0;
  444.             byteP = flags;
  445.             while (byteP < byteP2)
  446.             {   if ( (flag = *byteP++) & XSHORT )
  447.                 {   if ( flag & SHORT_X_IS_POS )
  448.                         z += *p++;
  449.                     else
  450.                         z -= *p++;
  451.                 }
  452.                 else if ( !(flag & NEXT_X_IS_ZERO) )        /* This means we have a 2 byte vector */
  453.                 {   z += (short)(*p++) << 8;
  454.                     z += *p++;
  455.                 }
  456.                 if (xCoord)
  457.                     *xCoord++ = z;
  458.             }
  459.         
  460.             /* Now Do Y */
  461.             if (yCoord)
  462.             {   z = 0;
  463.                 byteP = flags;
  464.                 while (byteP < byteP2)
  465.                 {   if ( (flag = *byteP++) & YSHORT )
  466.                     {   if ( flag & SHORT_Y_IS_POS )
  467.                             z += *p++;
  468.                         else
  469.                             z -= *p++;
  470.                     }
  471.                     else if ( !(flag & NEXT_Y_IS_ZERO) )    /* This means we have a 2 byte vector */
  472.                     {   z += (short)(*p++) << 8;
  473.                         z += *p++;
  474.                     }
  475.                     *yCoord++ = z;
  476.                 }
  477.             }
  478.             TTDisposPtr(flags);
  479.         }
  480.     }
  481.     TTDisposPtr(glyphData);
  482.     
  483.     return points;
  484. }
  485.  
  486. void ComputeGlyphBBox(register glyphBoundingBox* bbox, const short xArray[], const short yArray[], int counter)
  487. {
  488.     register int count = counter;
  489.     register const short* oox = xArray;
  490.     register const short* ooy = yArray;
  491.  
  492.     count--;
  493.     bbox->xMin = bbox->xMax = *oox++;
  494.     bbox->yMin = bbox->yMax = *ooy++;
  495.  
  496.     if (count > 0)
  497.         do
  498.         {   register short coord = *oox++;
  499.             if (bbox->xMin > coord)
  500.                 bbox->xMin = coord;
  501.             else if (bbox->xMax < coord)
  502.                 bbox->xMax = coord;
  503.     
  504.             coord = *ooy++;
  505.             if (bbox->yMin > coord)
  506.                 bbox->yMin = coord;
  507.             else if (bbox->yMax < coord)
  508.                 bbox->yMax = coord;
  509.         } while (--count);
  510. }
  511.  
  512. /*
  513.  *  This guy only works with non-composits. This should be fixed.
  514.  */
  515. void SetFontGlyphOutline(gxFont fontID, long glyphIndex, long contourCount, const short endPoint[], const unsigned char onCurve[],
  516.                     const short xCoord[], const short yCoord[], long instructionCount, const unsigned char instructions[],
  517.                     const glyphBoundingBox* bbox)
  518. {
  519.     long size, points;
  520.     void* data;
  521.     short* sp;
  522.  
  523.     if (contourCount == 0)
  524.     {   size = 0;
  525.         goto FINISH;
  526.     }
  527.  
  528.     points = endPoint[contourCount - 1] + 1;
  529.  
  530.     /*  Worst case size
  531.     */
  532.     size =  sizeof(short)               /* contours */
  533.             + 4 * sizeof(short)         /* bounds       */
  534.             + contourCount * sizeof(short)  /* ep[]     */
  535.             + sizeof(short)             /* instrCount   */
  536.             + instructionCount          /* instr[]  */
  537.             + points * sizeof(char)     /* flags[]      */
  538.             + points * sizeof(short)        /* x[]      */
  539.             + points * sizeof(short);       /* y[]      */
  540.  
  541.     data = TTNewPtr(size);
  542.  
  543.     sp = (short*)data;
  544.     *sp++ = contourCount;
  545.     if (bbox)
  546.     {   CopyBytes(bbox, sp, 4 * sizeof(short));
  547. #ifdef debugging
  548.         {   glyphBoundingBox tempBBox;
  549.             ComputeGlyphBBox(&tempBBox, xCoord, yCoord, points);
  550.             if (!EqualBytes(&tempBBox, bbox, 4 * sizeof(short)))
  551.                 Debugger();
  552.         }
  553. #endif
  554.     }
  555.     else
  556.         ComputeGlyphBBox((glyphBoundingBox*)sp, xCoord, yCoord, points);
  557.     sp += 4;
  558.  
  559.     CopyBytes(endPoint, sp, contourCount * sizeof(short));
  560.     sp += contourCount;
  561.  
  562.     *sp++ = instructionCount;
  563.     if (instructionCount)
  564.     {   CopyBytes(instructions, sp, instructionCount);
  565.         sp = (short*)((char*)sp + instructionCount);
  566.     }
  567.  
  568.     {   unsigned char* flags, *flagsPtr;
  569.         int i, x, y, count;
  570.         char* bp;
  571.         const short* xPtr = xCoord;
  572.         const short* yPtr = yCoord;
  573.  
  574.         flagsPtr = (unsigned char *) TTNewPtr(points);
  575.         flags = flagsPtr;
  576.         x = y = 0;
  577.         count = points;
  578.         while (count--)
  579.         {   unsigned char flag = *onCurve++;
  580.             int newy, newx = *xPtr++;
  581.             int tmp = newx - x;
  582.             if ( tmp == 0 )
  583.                 flag |= NEXT_X_IS_ZERO;
  584.             else if ( tmp <= 255 && tmp >= -255 )
  585.             {   flag |= XSHORT;
  586.                 if (tmp > 0)
  587.                     flag |= SHORT_X_IS_POS;
  588.             }
  589.             newy = *yPtr++;
  590.             tmp = newy - y;
  591.             if ( tmp == 0 )
  592.                 flag |= NEXT_Y_IS_ZERO;
  593.             else if ( tmp <= 255 && tmp >= -255 )
  594.             {   flag |= YSHORT;
  595.                 if (tmp > 0)
  596.                     flag |= SHORT_Y_IS_POS;
  597.             }
  598.             x = newx;
  599.             y = newy;
  600.             *flags++ = flag;
  601.         }
  602.  
  603.         /* write out flags */
  604.         bp = (char*)sp;
  605.         for (i = 0; i < points; i++)
  606.         {   int k, count = 0;
  607.  
  608.             for ( k = i+1; k < points && flagsPtr[k] == flagsPtr[i] && count < 255; k++)
  609.                 count++;
  610.             if ( count > 1 )
  611.             {   *bp++ = flagsPtr[i] | REPEAT_FLAGS;
  612.                 *bp++ = count;
  613.                 i += count;
  614.             }
  615.             else
  616.                 *bp++ = flagsPtr[i];
  617.         }
  618.  
  619.         /* write out x coordinates */
  620.         x = 0;
  621.         count = points;
  622.         flags = flagsPtr;
  623.         while (count--)
  624.         {   int newx = *xCoord++;
  625.             int tmp = newx - x;
  626.             int flag = *flags++;
  627.  
  628.             if (flag & XSHORT)
  629.             {   if (!(flag & SHORT_X_IS_POS))
  630.                     tmp = -tmp;
  631.                 *bp++ = tmp;
  632.             }
  633.             else if (!(flag & NEXT_X_IS_ZERO))
  634.             {   *bp++ = tmp >> 8;
  635.                 *bp++ = tmp & 255;
  636.             }
  637.             x = newx;
  638.         }
  639.     
  640.         /* write out y coordinates */
  641.         y = 0;
  642.         count = points;
  643.         flags = flagsPtr;
  644.         while (count--)
  645.         {   int newy = *yCoord++;
  646.             int tmp = newy - y;
  647.             int flag = *flags++;
  648.  
  649.             if (flag & YSHORT)
  650.             {   if (!(flag & SHORT_Y_IS_POS))
  651.                     tmp = -tmp;
  652.                 *bp++ = tmp;
  653.             }
  654.             else if (!(flag & NEXT_Y_IS_ZERO))
  655.             {   *bp++ = tmp >> 8;
  656.                 *bp++ = tmp & 255;
  657.             }
  658.             y = newy;
  659.         }
  660.  
  661.         IfDebug(size < bp - (char*)data,(unsigned char *) "\pOverwrote buffer for packed data");
  662.         size = bp - (char*)data;        /* get the actual (smaller) size */
  663.         TTDisposPtr(flagsPtr);
  664.     }
  665. FINISH:
  666.     SetFontGlyphData(fontID, glyphIndex, size, data);
  667.     TTDisposPtr(data);
  668. }
  669.  
  670. #define CountControlLongs(n)    ((n) + 31 >> 5)
  671. #define NextPath(p)         (gxPath*)((p)->controlBits + CountControlLongs((p)->vectors) + ((p)->vectors << 1))
  672. #define NextPoly(p)         (gxPolygon*)((p)->vector + (p)->vectors)
  673.  
  674. static unsigned char IsOnCurve(gxShapeType typeID, gxPaths* p, int indexBase0)
  675. {
  676.     unsigned char onCurve = ONCURVE;
  677.  
  678.     if (typeID == gxPathType)
  679.     {   long* controlBits;
  680.         gxPath* aPath = p->contour;
  681.  
  682.         while (indexBase0 >= aPath->vectors)
  683.         {   indexBase0 -= aPath->vectors;
  684.             aPath = NextPath(aPath);
  685.         }
  686.         controlBits = aPath->controlBits + (indexBase0 >> 5);
  687.         indexBase0 &= 31;
  688.         onCurve = (*controlBits >> 31 - indexBase0) & 1 ? 0 : ONCURVE;
  689.     }
  690.     return onCurve;
  691. }
  692.  
  693. static gxPoint* IndexedPoint(gxShapeType typeID, gxPaths* p, int indexBase0)
  694. {
  695.     if (typeID == gxPathType)
  696.     {   gxPath* aPath = (gxPath*)p->contour;
  697.  
  698.         while (indexBase0 >= aPath->vectors)
  699.         {   indexBase0 -= aPath->vectors;
  700.             aPath = NextPath(aPath);
  701.         }
  702.         return (gxPoint*)(aPath->controlBits + CountControlLongs(aPath->vectors)) + indexBase0;
  703.     }
  704.     else
  705.     {   gxPolygon* poly = (gxPolygon*)p->contour;
  706.  
  707.         while (indexBase0 >= poly->vectors)
  708.         {   indexBase0 -= poly->vectors;
  709.             poly = NextPoly(poly);
  710.         }
  711.         return poly->vector + indexBase0;
  712.     }
  713. }
  714.  
  715. /*
  716.  *  Assumes the outline is at upem.16, so I can just call FixRound
  717.  *  on the coordinates and they will be in upem.
  718.  *
  719.  *  Only works on gxPaths and gxPolygons.
  720.  */
  721. void SetFontGlyphShape(gxFont fontID, long glyphIndex, gxShape s)
  722. {
  723.     int contours, points, i;
  724.     gxShapeType typeID;
  725.     gxPaths* thePath;
  726.     short* xCoord, *yCoord, *endPoint;
  727.     unsigned char* onCurve;
  728.     long attr;
  729.  
  730.     typeID = GXGetShapeType(s);
  731.     contours = GXCountShapeContours(s);
  732.     points = GXCountShapePoints(s, 0);
  733.  
  734.     endPoint = (short *) TTNewPtr((contours + 2 * points) * sizeof(short) + points);
  735.     xCoord = endPoint + contours;
  736.     yCoord = xCoord + points;
  737.     onCurve = (unsigned char*)(yCoord + points);
  738.     
  739.     attr = GXGetShapeAttributes(s);
  740.     GXSetShapeAttributes(s, attr | gxDirectShape);
  741.     GXLockShape(s);
  742.     thePath = (gxPaths *) GXGetShapeStructure(s, 0);
  743.  
  744.     {   int ep = -1;
  745.  
  746.         for (i = 0; i < contours; i++)
  747.         {   ep += GXCountShapePoints(s, i + 1);
  748.             endPoint[i] = ep;
  749.         }
  750.     }
  751.     for (i = 0; i < points; i++)
  752.     {   gxPoint* pt = IndexedPoint(typeID, thePath, i);
  753.         xCoord[i] = FixedRound(pt->x);
  754.         yCoord[i] = - FixedRound(pt->y);
  755.         onCurve[i] = IsOnCurve(typeID, thePath, i);
  756.     }
  757.  
  758.     SetFontGlyphOutline(fontID, glyphIndex, contours, endPoint, onCurve, xCoord, yCoord, 0, nil, nil);
  759.  
  760.     GXUnlockShape(s);
  761.     GXSetShapeAttributes(s, attr);
  762.  
  763.     TTDisposPtr(endPoint);
  764. }
  765.  
  766. long GetFontGlyphData(gxFont fontID, long index, void* userCopy)
  767. {
  768.     short format;
  769.     long offset, length;
  770.  
  771.     {   long count = GXCountFontGlyphs(fontID);
  772.         if (index <= 0 || index > count) {
  773.             GXPostGraphicsWarning(font_glyph_index_out_of_range);
  774.             return -1;
  775.         }
  776.         index--;
  777.     }
  778.     {   sfntFontHeader* head = (sfntFontHeader*) GetFontTablePtr(fontID, fontHeaderTag);
  779.         format = head->indexToLocFormat;
  780.         TTDisposPtr(head);
  781.     }
  782.     {   void* location = GetFontTablePtr(fontID, indexToLocationTag);
  783.         if (format == SHORT_INDEX_TO_LOC_FORMAT)
  784.         {   unsigned short* loc = (unsigned short*)location + index;
  785.             offset = (long)loc[0] << 1;
  786.             length = ((long)loc[1] << 1) - offset;
  787.         }
  788.         else
  789.         {   long* loc = (long*)location + index;
  790.             offset = loc[0];
  791.             length = loc[1] - offset;
  792.         }
  793.         TTDisposPtr(location);
  794.     }
  795.     if (userCopy && length)
  796.         GXFindFontTableParts(fontID, glyphDataTag, offset, length, userCopy, nil);
  797.     return length;
  798. }
  799.  
  800. void SetFontGlyphData(gxFont fontID, long index, long newLength, void* data)
  801. {
  802.     Handle table;
  803.     long oldLength, offset, alignDelta, glyphs;
  804.     short locFormat;
  805.  
  806.     glyphs = GXCountFontGlyphs(fontID);
  807.     if (index <= 0 || index > glyphs)
  808.         return;
  809.     index--;
  810.  
  811.     {   sfntFontHeader* head = (sfntFontHeader*) GetFontTablePtr(fontID, fontHeaderTag);
  812.         locFormat = head->indexToLocFormat;
  813.         TTDisposPtr(head);
  814.     }
  815.     table = CopyFontTable(fontID, indexToLocationTag);
  816.     if (table)
  817.     {   if (locFormat == SHORT_INDEX_TO_LOC_FORMAT)
  818.         {   unsigned short* loc = (unsigned short*)*table + index;
  819.             unsigned short* stop = (unsigned short*)*table + glyphs + 1;
  820.             
  821.             offset = (long)*loc++ << 1;
  822.             oldLength = ((long)*loc << 1) - offset;
  823.             alignDelta = (WORD_ALIGN(newLength) - oldLength) / 2;
  824.             while (loc < stop)
  825.                 *loc++ += alignDelta;
  826.         }
  827.         else
  828.         {   long* loc = (long*)*table + index;
  829.             long* stop = (long*)*table + glyphs + 1;
  830.             
  831.             offset = *loc++;
  832.             oldLength = *loc - offset;
  833.             alignDelta = WORD_ALIGN(newLength) - WORD_ALIGN(oldLength);
  834.             while (loc < stop)
  835.                 *loc++ += alignDelta;
  836.         }
  837.  
  838.         HLock(table);
  839.         GXSetFontTable(fontID, 0, indexToLocationTag, GetHandleSize(table), *table);
  840.         DisposeHandle(table);
  841.     }
  842.  
  843.     GXSetFontTableParts(fontID, 0, glyphDataTag, offset, oldLength, WORD_ALIGN(newLength), data);
  844.     if (AINT_WORD_ALIGN(newLength))
  845.     {   long zero = 0;
  846.         GXSetFontTableParts(fontID, 0, glyphDataTag, offset + newLength, 1, 1, &zero);
  847.     }
  848. }
  849.  
  850.